package com.lcf.system.manager;

import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.lcf.base.constant.SysConstant;
import com.lcf.common.utils.ThreadUtils;
import com.lcf.framework.utils.TenantUtils;
import com.lcf.redis.enums.RedisCachePrefixEnum;
import com.lcf.redis.utils.RedisCacheUtils;
import com.lcf.system.entity.SysRole;
import com.lcf.system.entity.SysTenantUser;
import com.lcf.system.enums.SysRoleEnum;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 缓存
 *
 * @author lcf
 */
@Component
public class CacheManager {
    @Resource
    private RedisCacheUtils redisCacheUtils;
    @Resource
    private SysMenuManager sysMenuManager;
    @Resource
    private SysRoleManager sysRoleManager;

    /**
     * 删除菜单相关缓存
     */
    public void delMenuCache(Long menuId) {
        //删除菜单树缓存
        redisCacheUtils.del(RedisCachePrefixEnum.MENU_TREE.getKey());
        redisCacheUtils.del(RedisCachePrefixEnum.TENANT_MENU_TREE.getKey() + menuId);

        TenantUtils.ignoreTenantId(() -> {
            //删除租户管理员角色权限缓存
            List<SysRole> adminRoleList = Db.lambdaQuery(SysRole.class)
                    .eq(SysRole::getRoleCode, SysRoleEnum.ADMIN.getCode())
                    .list();

            List<Long> adminRoleIdList = CollectionUtils.isEmpty(adminRoleList) ? Collections.emptyList() :
                    adminRoleList.stream().map(SysRole::getId).toList();
            this.delRolePermissionCache(adminRoleIdList);

            //删除超级管理员用户菜单缓存
            this.delUserMenuCache(Collections.singletonList(SysConstant.PLATFORM_ADMIN_ID));

            if (menuId != null) {
                //删除角色权限缓存
                List<Long> roleIdList = sysMenuManager.getRoleIdsByMenuId(menuId);
                List<Long> allRole = new ArrayList<>(roleIdList);
                allRole.addAll(adminRoleIdList);
                this.delRolePermissionCache(allRole);

                //删除用户菜单缓存
                List<Long> userIds = sysRoleManager.getUserIdByRoleId(allRole);
                this.delUserMenuCache(userIds);
            } else {
                this.delRolePermissionCache(adminRoleIdList);

                List<Long> userIds = sysRoleManager.getUserIdByRoleId(adminRoleIdList);
                this.delUserMenuCache(userIds);
            }
        });
    }

    /**
     * 删除角色相关缓存
     */
    public void delRoleCache(long roleId) {
        TenantUtils.ignoreTenantId(() -> {
            //删除角色权限缓存
            this.delRolePermissionCache(Collections.singletonList(roleId));

            List<Long> userIds = sysRoleManager.getUserIdByRoleId(Collections.singletonList(roleId));
            //删除用户菜单缓存
            this.delUserMenuCache(userIds);
            //删除用户角色缓存
            this.delUserRoleCache(userIds);
        });
    }

    /**
     * 删除用户相关缓存
     */
    public void delUserCache(Long userId) {
        //删除用户菜单缓存
        this.delUserMenuCache(Collections.singletonList(userId));
        //删除用户角色缓存
        this.delUserRoleCache(Collections.singletonList(userId));
    }

    /**
     * 删除角色权限缓存
     */
    private void delRolePermissionCache(List<Long> roleIdList) {
        if (CollectionUtils.isEmpty(roleIdList)) {
            return;
        }

        roleIdList.forEach(roleId -> redisCacheUtils.del(RedisCachePrefixEnum.ROLE_PERMISSION.getKey(roleId)));
    }

    /**
     * 删除用户菜单缓存
     */
    private void delUserMenuCache(List<Long> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return;
        }

        TenantUtils.ignoreTenantId(() -> Db.lambdaQuery(SysTenantUser.class)
                .in(SysTenantUser::getUserId, userIds)
                .list()
                .forEach(sysTenantUser ->
                        redisCacheUtils.del(RedisCachePrefixEnum.USER_MENU.getKey(sysTenantUser.getUserId() + ":" + sysTenantUser.getTenantId()))));
    }

    /**
     * 删除用户角色缓存
     */
    private void delUserRoleCache(List<Long> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return;
        }

        TenantUtils.ignoreTenantId(() -> Db.lambdaQuery(SysTenantUser.class)
                .in(SysTenantUser::getUserId, userIds)
                .list()
                .forEach(sysTenantUser -> {
                            redisCacheUtils.del(RedisCachePrefixEnum.USER_ROLE.getKey(sysTenantUser.getUserId() + ":" + sysTenantUser.getTenantId()));
                            redisCacheUtils.del(RedisCachePrefixEnum.USER_ROLE_ID.getKey(sysTenantUser.getUserId() + ":" + sysTenantUser.getTenantId()));
                        }
                ));
    }
}
